<template>
  <z-paging :="fv.rootProps" ref="pagingRef">
    <template v-slot:[slotName]="scoped" v-for="slotName in fv.rootSlots">
      <slot :name="slotName" :="scoped"></slot>
    </template>
    <template v-slot:[slotName] v-for="slotName in variables.layoutSlot">
      <LoadPage :="loadPage" :load="load" v-if="config.isShowLoadPage(slotName)" />
      <view :class="['paging-' + slotName]">
        <slot :name="slotName"></slot>
      </view>
    </template>
    <template v-slot:[variables.DefaultSlots.refresher]="{ refresherStatus: rs }">
      <slot :name="variables.DefaultSlots.refresher">
        <RefresherStatus :status="rs" :root-props="fv.rootProps" />
      </slot>
    </template>
    <template v-slot:[slotName] v-for="slotName in variables.loadingMoreSlot">
      <slot :name="slotName">
        <LoadingMore :status="slotName" @reload="pagingRef?.doLoadMore('click')" :root-props="fv.rootProps" />
      </slot>
    </template>
    <template v-slot:[variables.DefaultSlots.empty]="{ isLoadFailed }">
      <slot :name="variables.DefaultSlots.empty">
        <Empty :success="!isLoadFailed" @reload="pagingRef?.refresh()" :root-props="fv.rootProps" />
      </slot>
    </template>
    <template v-slot:[variables.DefaultSlots.backToTop]>
      <slot :name="variables.DefaultSlots.backToTop">
        <view class="iconfont icon-back-to-top"></view>
      </slot>
    </template>
  </z-paging>
</template>

<script lang="ts" setup>
import { isEmpty, kebabToPascal, toStrFirstCase } from '@/utils'
import { PagingNS, variables } from '.'
import { computed, onBeforeUnmount, ref, useAttrs, useSlots, watch } from 'vue'
import LoadPage from '@/components/load-page/index.vue'
import RefresherStatus from './components/refresher-status.vue'
import LoadingMore from './components/loading-more.vue'
import Empty from './components/empty.vue'
import overallSituation, { LoadStatus } from '@/stores/overall-situation'
import type { LoadPageNS } from '@/components'
import { localFile } from '@/utils/local-file'
import { t } from '@/locale'
import { merge } from 'lodash'
import { Theme } from '@/utils/theme'

defineOptions({
  name: PagingNS.name
})
const props = defineProps(PagingNS.props)
const attrs = useAttrs() as Omit<PagingNS.Props, keyof typeof PagingNS.props>
const slots = useSlots()
const loadPageRef = ref<LoadPageNS.Instance>()
const pagingRef = ref<ZPagingRef>()
const fv = computed(() => {
  const newAttrs = Object.entries(attrs).reduce((p, c) => {
    const key = toStrFirstCase(kebabToPascal(c![0]))
    Reflect.set(p, key, c![1])
    return p
  }, <typeof attrs>{})
  const { fixed = true, modelValue, loadingMoreEnabled = true } = newAttrs
  const rootProps = merge(<ZPagingProps>{
    fixed,
    loadingMoreEnabled,
    autoShowBackToTop: true,
    backToTopBottom: fixed ? '40rpx' : '0px',
    showRefresherWhenReload: !isEmpty(modelValue),
    emptyViewErrorImg: localFile.getImage('components/paging-empty-error'),
    emptyViewErrorText: t('zp.emptyView.error'),
    emptyViewReloadText: t('zp.emptyView.reload'),
    emptyViewImg: localFile.getImage('components/paging-empty'),
    emptyViewText: t('zp.emptyView.title'),
    loadingMoreDefaultText: t('zp.loadingMore.default'),
    loadingMoreLoadingText: t('zp.loadingMore.loading'),
    loadingMoreNoMoreText: t('zp.loadingMore.noMore'),
    loadingMoreFailText: t('zp.loadingMore.fail'),
    refresherCompleteText: t('zp.refresher.complete'),
    refresherDefaultText: t('zp.refresher.default'),
    refresherRefreshingText: t('zp.refresher.refreshing'),
    refresherPullingText: t('zp.refresher.pulling'),
    [Theme.theme]: ''
  }, newAttrs, {
    class: [
      variables.ns.b,
      fixed && 'page-paging',
      variables.ns.s('empty', !isEmpty(modelValue) && !modelValue.length),
      variables.ns.s('hide-page', props.loadPage.hidePage)
    ],
  })
  const rootSlots = Object.keys(slots).filter(
    slotName => !Object.values(variables.DefaultSlots as object).includes(slotName))

  return {
    rootProps,
    rootSlots
  }
})
const config = {
  offWatch: () => { },
  isShowLoadPage(slotName: typeof variables.layoutSlot[number]) {
    const is = props.loadPage.showLoading ?? fv.value.rootProps.fixed
    return slotName === variables.DefaultSlots.bottom && is
  }
}

async function load() {
  switch (overallSituation.loadStatus) {
    case LoadStatus.init:
    case LoadStatus.load:
      await new Promise((resolve, reject) => {
        config.offWatch = watch(() => overallSituation.loadStatus, async () => {
          if (overallSituation.loadStatus === LoadStatus.success) {
            resolve(true)
          } else {
            try {
              await props.loadPage?.beforeLoad?.()
              reject(overallSituation.loadStatus)
            } catch (error) {
              reject(error)
            }
          }

          config.offWatch()
        })
      })
      await props.loadPage?.beforeLoad?.()
    case LoadStatus.success: await props.loadPage?.load()
    case LoadStatus.fail: 
      throw {}
  }
}

onBeforeUnmount(() => {
  config.offWatch()
})

defineExpose({
  pagingRef,
  loadPageRef
})
</script>